package com.hirsi;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.hirsi.core.annotation.RequestMapping;
import com.hirsi.core.util.ConfigUtil;
import com.hirsi.core.util.DbUtil;
import com.hirsi.core.util.TorrentUtil;
import com.hirsi.core.vo.result.ResponseResult;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.StaticHandler;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Set;

public class ApplicationStarter extends AbstractVerticle {
    public static void main(String[] args) {
        Vertx.vertx().deployVerticle(new ApplicationStarter());
    }


    @Override
    public void start() {
        ConfigUtil.init();
        DbUtil.init();
        TorrentUtil.init();
        try {
            //给config运行权限
            Runtime.getRuntime().exec("chmod -R 755 /config");
            Runtime.getRuntime().exec("chmod -R 755 /tmp");
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 创建HttpServer
        HttpServer server = vertx.createHttpServer();
        // 创建路由对象
        Router router = Router.router(vertx);
        //接收boyd
        router.route().handler(BodyHandler.create());

        //动态注册路由
        initController(router);

        // 创建静态文件处理器并将其添加到路由上
        StaticHandler staticHandler = StaticHandler.create("webapp").setCachingEnabled(false);
        router.route("/*").handler(staticHandler);
        server.requestHandler(router).listen(8082);
    }

    /**
     * 注册controller
     * @param router
     */
    private void initController(Router router) {
        String basePack  = this.getClass().getPackage().getName();
        Set<Class<?>> classes = ClassUtil.scanPackage(basePack);
        for (Class<?> clazz : classes) {
            RequestMapping classMapping = clazz.getAnnotation(RequestMapping.class);
            if (classMapping != null) {
                Method[] methods = clazz.getMethods();
                String rootUrl = classMapping.value();
                if (methods != null && methods.length > 0) {
                    try {
                        Object object = clazz.newInstance();
                        for (Method method : methods) {
                            RequestMapping mapping = method.getAnnotation(RequestMapping.class);
                            if (mapping != null) {
                                String url = mapping.value();
                                if ("/".equals(rootUrl)) {
                                    if (!url.startsWith("/")) url = rootUrl + url;
                                } else {
                                    if (!rootUrl.startsWith("/")) rootUrl = "/" + rootUrl;
                                    if (!rootUrl.endsWith("/") && !url.startsWith("/")) url = "/" + url;
                                    url = rootUrl + url;
                                }
                                url = "/api" + url;
                                router.route(url).handler(ctx -> {
                                    try {
                                        Parameter[] parameters = method.getParameters();
                                        Object[] params = new Object[parameters.length];
                                        if (parameters != null && parameters.length > 0) {
                                            for (int i = 0; i < parameters.length; i++) {
                                                Class<?> type = parameters[i].getType();
                                                Object param = type.newInstance();
                                                Field[] fields = type.getDeclaredFields();
                                                if (ctx.request().params().size() > 0) {
                                                    for (Field field : fields) {
                                                        field.setAccessible(true);
                                                        String value = ctx.request().getParam(field.getName());
                                                        if (value != null && !value.isEmpty()) {
                                                            if (field.getType() == Integer.class) field.set(param, Integer.parseInt(value));
                                                            else field.set(param, value);
                                                        }
                                                    }
                                                } else if (ctx.body() != null) {
                                                    param = JSONUtil.toBean(ctx.body().asString(), type);
                                                }
                                                params[i] = param;
                                            }
                                        }
                                        Object result = method.invoke(object, params);
                                        ctx.response().putHeader("Content-type", "application/json; charset=utf-8")
                                                .end(JSONUtil.toJsonStr(ResponseResult.success(result)));
                                    } catch (IllegalAccessException | InvocationTargetException e) {

                                        ctx.response().putHeader("Content-type", "application/json; charset=utf-8")
                                                .end(JSONUtil.toJsonStr(ResponseResult.fail(e.getMessage())));
                                    } catch (Exception e) {

                                        ctx.response().putHeader("Content-type", "application/json; charset=utf-8")
                                                .end(JSONUtil.toJsonStr(ResponseResult.fail(e.getMessage())));
                                    }
                                });
                            }
                        }
                    } catch (InstantiationException | IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }
}